package com.xinzhidi.web.plot.service.impl;

import cn.hutool.core.thread.ThreadUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinzhidi.common.constant.CacheConstants;
import com.xinzhidi.common.core.domain.model.LoginUser;
import com.xinzhidi.common.core.page.TableDataInfo;
import com.xinzhidi.common.core.redis.RedisCache;
import com.xinzhidi.common.core.text.Convert;
import com.xinzhidi.common.exception.ServiceException;
import com.xinzhidi.common.exception.job.TaskException;
import com.xinzhidi.common.utils.DateUtils;
import com.xinzhidi.common.utils.SecurityUtils;
import com.xinzhidi.common.utils.StringUtils;
import com.xinzhidi.common.utils.bean.BeanUtils;
import com.xinzhidi.quartz.domain.SysJob;
import com.xinzhidi.quartz.service.ISysJobService;
import com.xinzhidi.system.service.ISysUserService;
import com.xinzhidi.web.build.domain.BuildUnit;
import com.xinzhidi.web.build.domain.CBuild;
import com.xinzhidi.web.build.mapper.CBuildMapper;
import com.xinzhidi.web.build.service.IBuildUnitService;
import com.xinzhidi.web.city.domain.City;
import com.xinzhidi.web.city.domain.vo.CityVo;
import com.xinzhidi.web.city.service.CityService;
import com.xinzhidi.web.custommodel.domain.CustomModel;
import com.xinzhidi.web.custommodel.service.CustomModelService;
import com.xinzhidi.web.house.domain.Household;
import com.xinzhidi.web.house.service.IHouseholdService;
import com.xinzhidi.web.netty.utils.SecurityAdminUtils;
import com.xinzhidi.web.plot.domain.dto.CPlotAddDto;
import com.xinzhidi.web.plot.domain.dto.CPlotListDto;
import com.xinzhidi.web.plot.domain.dto.CPlotUpdDto;
import com.xinzhidi.web.plot.domain.entity.CPlot;
import com.xinzhidi.web.plot.domain.vo.CPlotInfoVo;
import com.xinzhidi.web.plot.domain.vo.CPlotListVo;
import com.xinzhidi.web.plot.domain.vo.PlotListVo;
import com.xinzhidi.web.plot.domain.vo.SelectVo;
import com.xinzhidi.web.plot.mapper.CPlotMapper;
import com.xinzhidi.web.plot.service.ICPlotService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * 小区Service业务层处理
 *
 * @author ruoyi
 * @date 2023-05-19
 */
@Service
public class CPlotServiceImpl extends ServiceImpl<CPlotMapper, CPlot> implements ICPlotService {
    @Autowired
    private CPlotMapper cPlotMapper;

    @Autowired
    private CBuildMapper cBuildMapper;

    @Autowired
    private CustomModelService customModelService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private CityService cityService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private ISysJobService sysJobService;

    @Autowired
    private IBuildUnitService buildUnitService;

    @Autowired
    private IHouseholdService householdService;

    /**
     * 查询小区
     *
     * @param id 小区主键
     * @return 小区
     */
    @Override
    public CPlotInfoVo selectCPlotById(Long id) {
        CPlot cPlot = cPlotMapper.selectById(id);
        CPlotInfoVo infoVo = new CPlotInfoVo();
        BeanUtils.copyProperties(cPlot, infoVo);
        return infoVo;
    }

    /**
     * 查询小区列表
     *
     * @param dto 查询小区dto
     * @return 小区
     */
    @Override
    public TableDataInfo<CPlotListVo> selectCPlotList(CPlotListDto dto , List<Long> userPlotIds) {
        TableDataInfo info;
        LambdaQueryWrapper<CPlot> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StringUtils.isNotEmpty(dto.getParkName()), CPlot::getParkName, dto.getParkName()).eq(StringUtils.isNotEmpty(dto.getProvince()), CPlot::getProvince, dto.getProvince()).eq(StringUtils.isNotEmpty(dto.getCity()), CPlot::getCity, dto.getCity()).eq(StringUtils.isNotEmpty(dto.getArea()), CPlot::getArea, dto.getArea());
        wrapper.orderByDesc(CPlot::getCreateTime);
        if (CollectionUtils.isNotEmpty(userPlotIds)) {
            wrapper.in(CPlot::getId, userPlotIds);
        }
        List<CPlot> list = cPlotMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(list)) {
            return TableDataInfo.getDataTable(Lists.newArrayList());
        }
        Map<String, City> areaMap = cityService.getAreaMap();
        List<CPlotListVo> voList = Lists.newArrayList();
        // 多线程处理
        //初始化线程数量
        CountDownLatch countDownLatch = ThreadUtil.newCountDownLatch(list.size());
        for (CPlot domain : list) {
            List<CPlotListVo> finalInstructionList = voList;
            ThreadUtil.execute(() -> {
                CPlotListVo vo = new CPlotListVo();
                LambdaQueryWrapper<CBuild> queryWrapper = Wrappers.lambdaQuery();
                queryWrapper.eq(CBuild::getPlotId, domain.getId());
                queryWrapper.eq(CBuild::getDelFlag, 0);
                Integer integer = cBuildMapper.selectCount(queryWrapper);
                CPlot heartArea = cPlotMapper.selectHeartArea(domain.getId());
                BeanUtils.copyProperties(domain, vo);
                String modelIds = domain.getModelIds();
                if (StringUtils.isNotBlank(modelIds)) {
                    List<CustomModel> modelList = customModelService.getModelByIds(modelIds);
                    vo.setCustomModels(modelList);
                }
                vo.setProvinceName(areaMap.get(vo.getProvince()) == null ? "暂无" : areaMap.get(vo.getProvince()).getName());
                vo.setCityName(areaMap.get(vo.getCity()) == null ? "暂无" : areaMap.get(vo.getCity()).getName());
                vo.setAreaName(areaMap.get(vo.getArea()) == null ? "暂无" : areaMap.get(vo.getArea()).getName());
                vo.setAreaName(areaMap.get(vo.getArea()) == null ? "暂无" : areaMap.get(vo.getArea()).getName());
                vo.setCreateName(sysUserService.selectUserById(Convert.toLong(domain.getCreateBy())).getNickName());
                vo.setBuildNumber(Long.valueOf(integer));
                vo.setHeatArea(heartArea.getHeatArea());
                vo.setHeatUser(heartArea.getHeatUser());
                finalInstructionList.add(vo);
                //调用线程计数器-1
                countDownLatch.countDown();
            });
            voList.addAll(finalInstructionList);
        }
        //唤醒主线程
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //根据小区id排序
        voList = voList.stream().sorted(Comparator.comparing(CPlotListVo::getId))
                .collect(Collectors.toList());
        return TableDataInfo.getDataTable(voList);
    }

    /**
     * 查询小区列表
     *
     * @param dto 查询小区dto
     * @return 小区
     */
    @Override
    public TableDataInfo<SelectVo> listCPlotSelect(CPlotListDto dto) {
        TableDataInfo info;
        List<CPlot> list;
        List<Long> userPlotIds = SecurityAdminUtils.getUserPlotIds();
        LambdaQueryWrapper<CPlot> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StringUtils.isNotEmpty(dto.getParkName()), CPlot::getParkName, dto.getParkName());
        wrapper.orderByDesc(CPlot::getCreateTime);
        if (CollectionUtils.isNotEmpty(userPlotIds)) {
            wrapper.in(CPlot::getId, userPlotIds);
        }
        list = cPlotMapper.selectList(wrapper);

        info = TableDataInfo.getDataTable(list, (domain -> {
            SelectVo vo = new SelectVo();
            vo.setLabel(domain.getParkName());
            vo.setValue(domain.getId().toString());
            vo.setCityCode(domain.getCity());
            return vo;
        }));
        return info;
    }

    /**
     * 新增小区
     *
     * @param dto 新增小区dto
     * @return 结果
     */
    @Override
    public int insertCPlot(CPlotAddDto dto) throws SchedulerException, TaskException {
        if (CollectionUtils.isNotEmpty(list(new LambdaQueryWrapper<>(CPlot.class).eq(CPlot::getParkName, dto.getParkName())))) {
            throw new ServiceException(dto.getParkName() + "已存在！");
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        CPlot cPlot = new CPlot();
        BeanUtils.copyProperties(dto, cPlot);
        cPlot.setCreateBy(loginUser.getUserId().toString());
        int num = cPlotMapper.insert(cPlot);
        String key = loginUser.getUserId() + CacheConstants.LOGIN_USER_PLOT_IDS;
        List<Long> plotList = redisCache.getCacheList(key);
        redisCache.deleteObject(key);
        if (CollectionUtils.isEmpty(plotList)) {
            plotList = Lists.newArrayList();
        }
        plotList.add(cPlot.getId());
        redisCache.setCacheList(key, plotList);
        //判断是否存在该小区定时任务，如果存在，则更新，不存在则新增
        this.checkHashTask(cPlot);
        return num;
    }

    /**
     * 修改小区
     *
     * @param dto 修改小区dto
     * @return 结果
     */
    @Override
    public int updateCPlot(CPlotUpdDto dto) throws SchedulerException, TaskException {
        LoginUser loginUser = SecurityUtils.getLoginUser();

        LambdaQueryWrapper<CPlot> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CPlot::getParkName, dto.getParkName()).ne(CPlot::getId, dto.getId());
        List<CPlot> list = cPlotMapper.selectList(wrapper);

        if (CollectionUtils.isNotEmpty(list)) {
            throw new ServiceException(dto.getParkName() + "已存在！");
        }

        CPlot cPlot = new CPlot();
        BeanUtils.copyProperties(dto, cPlot);
        cPlot.setUpdateBy(loginUser.getUserId().toString());
        cPlot.setUpdateTime(DateUtils.getNowDate());
        redisCache.deleteObject("plotNameById" + dto.getId());
        //判断是否存在该小区定时任务，如果存在，则更新，不存在则新增
        this.checkHashTask(cPlot);
        return cPlotMapper.updateById(cPlot);
    }

    public void checkHashTask(CPlot plot) throws SchedulerException, TaskException {
        String cronExpression = "0 0 0/" + plot.getIntervalTime() + " * * ?";
        SysJob sysJob = sysJobService.getJobByPlotId(plot.getId());
        if (sysJob != null && sysJob.getJobId() != null) {
            sysJob.setCronExpression(cronExpression);
            sysJobService.updateJob(sysJob);
        } else {
            sysJob = new SysJob();
            sysJob.setJobName("小区【" + plot.getParkName() + "】自动抄表定时任务");
            sysJob.setJobGroup("SYSTEM");
            sysJob.setInvokeTarget("automaticMeterReadTask.ryMultipleParams(" + plot.getId() + ")");
            sysJob.setCronExpression(cronExpression);
            sysJob.setMisfirePolicy("1");
            sysJob.setConcurrent("1");
            sysJob.setStatus("0");
            sysJobService.insertJob(sysJob);
        }

    }

    /**
     * 批量删除小区
     *
     * @param ids 需要删除的小区主键
     * @return 结果
     */
    @Override
    public int deleteCPlotByIds(Long[] ids) {
        //删除小区下的住户
        LambdaQueryWrapper<Household> householdWrapper = Wrappers.lambdaQuery();
        householdWrapper.in(Household::getPlotId, ids);
        householdService.remove(householdWrapper);
        //删除小区下的单元
        LambdaQueryWrapper<BuildUnit> unitWrapper = Wrappers.lambdaQuery();
        unitWrapper.in(BuildUnit::getLotId, ids);
        buildUnitService.remove(unitWrapper);
        //删除小区下的楼栋
        LambdaQueryWrapper<CBuild> buildWrapper = Wrappers.lambdaQuery();
        buildWrapper.in(CBuild::getPlotId, ids);
        cBuildMapper.delete(buildWrapper);
        return cPlotMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除小区信息
     *
     * @param id 小区主键
     * @return 结果
     */
    @Override
    public int deleteCPlotById(Long id) {
        return cPlotMapper.deleteById(id);
    }

    @Override
    public List<CityVo> getPlotCityList() {
        return cPlotMapper.getPlotCityList();
    }

    @Override
    public PlotListVo selectlistCPlotNoPage() {
        List<Long> userPlotIds = SecurityAdminUtils.getUserPlotIds();
        LambdaQueryWrapper<CPlot> wrapper = Wrappers.lambdaQuery();
        wrapper.in(CollectionUtils.isNotEmpty(userPlotIds), CPlot::getId, userPlotIds);
        List<CPlot> cPlots = cPlotMapper.selectList(wrapper);
        PlotListVo plotListVo = new PlotListVo();
        plotListVo.setParkName(cPlots);
        LambdaQueryWrapper<CBuild> cBuildLambdaQueryWrapper = Wrappers.lambdaQuery();
        for (CPlot cPlot : cPlots) {
            cBuildLambdaQueryWrapper.eq(CBuild::getPlotId, cPlot.getId());
            List<CBuild> cBuilds = cBuildMapper.selectList(cBuildLambdaQueryWrapper);
            plotListVo.setBuildName(cBuilds);
        }
        return plotListVo;
    }

    @Override
    public String getNameById(Long id) {
        String name = redisCache.getCacheObject("plotNameById" + id);
        if (StringUtils.isEmpty(name)) {
            CPlot entity = cPlotMapper.selectById(id);
            if (StringUtils.isEmpty(entity.getParkName())) {
                name = "暂无";
            } else {
                name = entity.getParkName();
            }
            redisCache.setCacheObject("plotNameById" + id, name, 3600, TimeUnit.SECONDS);
        }
        return name;
    }

    @Override
    public boolean addOrUpdateBuildUnitNum(Integer num, Long plotId) {
        CPlot plot = this.getById(plotId);
        Integer buildNumber = plot.getBuildNumber();
        buildNumber = buildNumber + num;
        plot.setBuildNumber(buildNumber);
        return this.updateById(plot);
    }

    public List<City> getPlotCityWeather() {
        return cPlotMapper.getPlotCityWeather();
    }

    @Override
    public List<CPlot> getAllPlot() {
        return this.baseMapper.selectCPlotList(new CPlot());
    }

}
